package service

import (
	"boy-go/modules/system/model"
	"boy-go/modules/system/repository"
	"boy-go/modules/system/vo"
	"boy-go/pkg/request"
	"boy-go/pkg/security"
	"boy-go/pkg/xerror"
	"fmt"
	"github.com/jinzhu/copier"
	"gorm.io/gorm"
	"time"
)

func NewSysRoleService() SysRoleService {
	return &sysRoleService{
		SysRoleRepo:     repository.NewSysRoleRepository(),
		SysUserRoleRepo: repository.NewSysUserRoleRepository(),
	}
}

type sysRoleService struct {
	SysRoleRepo     *repository.SysRoleRepository
	SysUserRoleRepo *repository.SysUserRoleRepository
}

// GetById 根据id获取配置信息
func (s *sysRoleService) GetById(roleId int64) (*vo.SysRoleModel, error) {
	m, err := s.SysRoleRepo.GetById(roleId)
	if err != nil {
		return nil, err
	}
	rsp := new(vo.SysRoleModel)
	if err := copier.Copy(rsp, m); err != nil {
		return nil, err
	}
	return rsp, nil
}
func (s *sysRoleService) SelectRoleAll() []*vo.SysRoleModel {
	list, _, err := s.SysRoleRepo.List(nil, nil)
	if err != nil {
		return nil
	}
	itemList := make([]*vo.SysRoleModel, 0)
	for _, v := range list {
		item := new(vo.SysRoleModel)
		if err := copier.Copy(item, &v); err != nil {
			continue
		}
		itemList = append(itemList, item)
	}
	return itemList
}
func (s *sysRoleService) List(req *vo.QuerySysRoleReq) (*vo.ListSysRoleRsp, error) {

	var page = &request.PageRequest{
		PageNum:  req.PageNum,
		PageSize: req.PageSize,
	}

	list, total, err := s.SysRoleRepo.List(req, page)

	if err != nil {
		return nil, err
	}

	itemList := make([]*vo.SysRoleModel, 0)
	for _, v := range list {
		item := new(vo.SysRoleModel)
		if err := copier.Copy(item, &v); err != nil {
			continue
		}
		itemList = append(itemList, item)
	}
	return &vo.ListSysRoleRsp{
		List:  itemList,
		Total: total,
	}, nil
}

// Add 添加角色表
func (s *sysRoleService) Add(req *vo.AddSysRoleReq) (*vo.AddSysRoleRsp, error) {
	loginUser := security.GetLoginUser()
	m := new(model.SysRole)
	err := copier.Copy(m, req)
	if err != nil {
		return nil, err
	}
	currentTime := time.Now()
	m.DelFlag = "0"
	m.DataScope = "1"
	m.CreateBy = &loginUser.UserName
	m.CreateAt = &currentTime
	err = s.SysRoleRepo.DB.Transaction(func(tx *gorm.DB) error {
		dbErr := tx.Model(&model.SysRole{}).Save(m).Error
		if dbErr != nil {
			return dbErr
		}
		roleMenus := make([]*model.SysRoleMenu, 0)
		for _, menuId := range req.MenuIds {
			roleMenus = append(roleMenus, &model.SysRoleMenu{
				RoleId: m.RoleId,
				MenuId: *menuId,
			})
		}
		dbErr = tx.Model(&model.SysRoleMenu{}).CreateInBatches(roleMenus, 100).Error
		return dbErr
	})
	if err != nil {
		return nil, err
	}
	return &vo.AddSysRoleRsp{
		RoleId: m.RoleId,
	}, nil
}

// Edit 修改角色表
func (s *sysRoleService) Edit(req *vo.EditSysRoleReq) (*vo.EditSysRoleRsp, error) {
	m := new(model.SysRole)
	err := copier.Copy(m, req)
	if err != nil {
		return nil, err
	}
	//事务
	err = s.SysRoleRepo.DB.Transaction(func(tx *gorm.DB) error {
		dbErr := tx.Model(&model.SysRole{}).Where("role_id = ?", m.RoleId).Omit("role_id").Updates(m).Error
		if dbErr != nil {
			return dbErr
		}
		// 删除角色权限
		dbErr = tx.Model(&model.SysRoleMenu{}).Where("role_id = ?", m.RoleId).Delete(&model.SysRoleMenu{}).Error
		if dbErr != nil {
			return dbErr
		}
		roleMenus := make([]*model.SysRoleMenu, 0)
		for _, menuId := range req.MenuIds {
			roleMenus = append(roleMenus, &model.SysRoleMenu{
				RoleId: m.RoleId,
				MenuId: *menuId,
			})
		}
		// 批量插入
		dbErr = tx.Model(&model.SysRoleMenu{}).CreateInBatches(roleMenus, 100).Error
		return dbErr
	})
	if err != nil {
		return nil, err
	}
	return &vo.EditSysRoleRsp{
		RoleId: m.RoleId,
	}, nil
}
func _insertRoleDept(tx *gorm.DB, roleId int64, deptIds []*int64) error {
	if len(deptIds) > 0 {
		ms := make([]*model.SysRoleDept, 0)
		for _, id := range deptIds {
			ms = append(ms, &model.SysRoleDept{
				RoleId: roleId,
				DeptId: *id,
			})
		}
		//批量保存
		dbErr := tx.Model(&model.SysRoleDept{}).CreateInBatches(ms, 200).Error
		return dbErr
	}
	return nil
}
func (s *sysRoleService) AuthDataScope(req *vo.EditSysRoleReq) error {
	err := s.SysRoleRepo.DB.Transaction(func(tx *gorm.DB) error {
		m := &model.SysRole{}
		dbErr := copier.Copy(&m, req)
		if dbErr != nil {
			return dbErr
		}
		dbErr = tx.Model(&model.SysRole{}).Where("role_id = ?", req.RoleId).Omit("role_id").Updates(m).Error
		if dbErr != nil {
			return dbErr
		}
		dbErr = tx.Model(&model.SysRoleDept{}).Where("role_id = ?", req.RoleId).Delete(&model.SysRoleMenu{}).Error
		if dbErr != nil {
			return dbErr
		}
		return _insertRoleDept(tx, req.RoleId, req.DeptIds)
	})
	return err
}

// Del 删除角色表
func (s *sysRoleService) Del(roleId int64) error {
	return s.SysRoleRepo.Delete(roleId)
}
func (s *sysRoleService) DeleteRoleByIds(roleIds []*int64) error {
	if len(roleIds) > 0 {
		for _, roleId := range roleIds {
			err := s.CheckRoleAllowed(roleId)
			if err != nil {
				return err
			}
			err = s.CheckRoleDataScope(*roleId)
			if err != nil {
				return err
			}
			role, err := s.SysRoleRepo.GetById(*roleId)
			if err != nil {
				return err
			}
			if s.CountUserRoleByRoleId(*roleId) > 0 {
				return xerror.NewArgument(fmt.Sprintf("%s已分配,不能删除", *role.RoleName))
			}
		}
	}
	err := s.SysRoleRepo.DB.Transaction(func(tx *gorm.DB) error {
		// 删除角色与菜单关联
		dbErr := tx.Model(&model.SysRoleMenu{}).Where("role_id in ?", roleIds).Delete(&model.SysRoleMenu{}).Error
		if dbErr != nil {
			return dbErr
		}
		//删除角色与部门关联
		dbErr = tx.Model(&model.SysRoleDept{}).Where("role_id in ?", roleIds).Delete(&model.SysRoleDept{}).Error
		if dbErr != nil {
			return dbErr
		}
		return tx.Model(&model.SysRole{}).Where("role_id in ?", roleIds).Delete(&model.SysRole{}).Error
	})
	return err
}
func (s *sysRoleService) CountUserRoleByRoleId(roleId int64) int64 {
	return s.SysUserRoleRepo.CountUserRoleByRoleId(roleId)
}
func (s *sysRoleService) CheckRoleNameUnique(roleId int64, roleName *string) bool {
	if roleName != nil {
		m, err := s.SysRoleRepo.GetByRoleName(*roleName)
		if err != nil {
			return false
		}
		if m.RoleId != roleId {
			return true
		}
	}
	return false
}
func (s *sysRoleService) CheckRoleKeyUnique(roleId int64, roleKey *string) bool {
	if roleKey != nil {
		m, err := s.SysRoleRepo.GetByRoleKey(*roleKey)
		if err != nil {
			return false
		}
		if m.RoleId != roleId {
			return true
		}
	}
	return false
}
func (s *sysRoleService) SelectRolesByUserId(userId int64) []*vo.SysRoleModel {
	userRoles := s.SysRoleRepo.SelectRolePermissionByUserId(userId)
	roles := s.SelectRoleAll()
	if roles != nil {
		for _, role := range roles {
			if len(userRoles) > 0 {
				for _, userRole := range userRoles {
					if role.RoleId == userRole.RoleId {
						role.Flag = true
					}
				}
			}
		}
	}
	return roles
}

// SelectRolePermissionByUserId 根据用户ID查询权限
func (s sysRoleService) SelectRolePermissionByUserId(userId int64) []*string {
	roles := s.SysRoleRepo.SelectRolePermissionByUserId(userId)
	permsSet := make([]*string, 0)
	if roles != nil {
		for _, role := range roles {
			permsSet = append(permsSet, role.RoleKey)
		}
	}
	return permsSet
}

func (s *sysRoleService) CheckRoleAllowed(roleId *int64) error {
	if roleId == nil || model.IsAdmin(roleId) {
		return xerror.NewArgument("不允许操作超级管理员角色")
	}
	return nil
}

func (s *sysRoleService) CheckRoleDataScope(roleIds ...int64) error {
	if len(roleIds) == 0 {
		return nil
	}
	loginUserId := security.GetLoginUserId()
	if !model.IsAdmin(loginUserId) {
		for _, roleId := range roleIds {
			roles, _, _ := s.SysRoleRepo.List(&vo.QuerySysRoleReq{RoleId: &roleId}, nil)
			if roles == nil || len(roles) == 0 {
				return xerror.NewArgument("没有权限访问角色数据")
			}
		}
	}
	return nil
}

func (s *sysRoleService) DeleteAuthUser(roleId int64, userId int64) error {
	return s.SysUserRoleRepo.DeleteUserRoleInfo(userId, roleId)
}
func (s *sysRoleService) DeleteAuthUsers(roleId int64, userIds []*int64) error {
	return s.SysUserRoleRepo.DeleteUserRoleInfos(roleId, userIds)
}
func (s *sysRoleService) InsertAuthUsers(roleId int64, userIds []*int64) error {
	userRoles := make([]*model.SysUserRole, 0)
	for _, userId := range userIds {
		userRole := &model.SysUserRole{
			RoleId: roleId,
			UserId: *userId,
		}
		userRoles = append(userRoles, userRole)
	}
	return s.SysUserRoleRepo.DB.CreateInBatches(userRoles, 200).Error
}
